package com.lx.mall.gateway.utils;

import com.alibaba.cloud.commons.lang.StringUtils;
import com.lx.mall.common.api.ResultCode;
import com.lx.mall.common.exception.GateWayException;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwsHeader;
import io.jsonwebtoken.Jwt;
import io.jsonwebtoken.Jwts;
import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.*;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;
import java.util.Map;

/**
 * @author lX
 * @version JDK 8
 * @className JwtUtils (此处以class为例)
 * @date 2024/12/17
 * @description JWT工具类
 */
public class JwtUtils {

  private static final Logger logger = LoggerFactory.getLogger(JwtUtils.class);

  /**
   * 认证服务器许可我们的网关的clientId(需要在oauth_client_details表中配置)
   */
  private static final String CLIENT_ID = "tulingmall-gateway";

  /**
   * 认证服务器许可我们的网关的client_secret(需要在oauth_client_details表中配置)
   */
  private static final String CLIENT_SECRET = "123123";



  /**
   * 认证服务器暴露的获取token_key的地址
   */
  private static final String AUTH_TOKEN_KEY_URL = "http://preferredmall-authcenter/oauth/token_key";

  /**
   * 请求头中的 token的开始
   */
  private static final String AUTH_HEADER = "bearer ";


  /**
   *方法实现说明: 通过远程调用获取认证服务器颁发jwt的解析的key
   * @param restTemplate
   * @return
   * @throws GateWayException
   */
  private static String getTokenKeyByRemoteCall(RestTemplate restTemplate) throws GateWayException {

    //第一步:封装请求头
    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
    headers.setBasicAuth(CLIENT_ID,CLIENT_SECRET);
    HttpEntity<MultiValueMap<String, String>> entity = new HttpEntity<>(null, headers);

    //第二步:远程调用获取token_key
    try {

      ResponseEntity<Map> response = restTemplate.exchange(AUTH_TOKEN_KEY_URL, HttpMethod.GET, entity, Map.class);

      String tokenKey = response.getBody().get("value").toString();

      logger.info("去认证服务器获取Token_Key:{}",tokenKey);

      return tokenKey;

    }catch (Exception e) {

      logger.error("远程调用认证服务器获取Token_Key失败:{}",e.getMessage());

      throw new GateWayException(ResultCode.GET_TOKEN_KEY_ERROR);
    }

  }

  /**
   * 生成公钥
   * @param restTemplate
   * @return
   * @throws GateWayException
   */
  public static PublicKey genPublicKey(RestTemplate restTemplate) throws GateWayException {

    String tokenKey = getTokenKeyByRemoteCall(restTemplate);
    try{

      //把获取的公钥开头和结尾替换掉
      String dealTokenKey =tokenKey.replaceAll("\\-*BEGIN PUBLIC KEY\\-*", "").replaceAll("\\-*END PUBLIC KEY\\-*", "").trim();

      java.security.Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());

      X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(Base64.decodeBase64(dealTokenKey));

      KeyFactory keyFactory = KeyFactory.getInstance("RSA");

      PublicKey publicKey = keyFactory.generatePublic(pubKeySpec);

      logger.info("生成公钥:{}",publicKey);

      return publicKey;

    }catch (Exception e) {

      logger.info("生成公钥异常:{}",e.getMessage());

      throw new GateWayException(ResultCode.GEN_PUBLIC_KEY_ERROR);
    }

  }

  /**
   * 校验token
   * @param authHeader
   * @param publicKey
   * @return
   */
  public static Claims validateJwtToken(String authHeader, PublicKey publicKey) {
    String token =null ;
    try{
      token = StringUtils.substringAfter(authHeader, AUTH_HEADER);

      Jwt<JwsHeader, Claims> parseClaimsJwt = Jwts.parser().setSigningKey(publicKey).parseClaimsJws(token);

      Claims claims = parseClaimsJwt.getBody();

      //log.info("claims:{}",claims);

      return claims;

    }catch(Exception e){

      logger.error("校验token异常:{},异常信息:{}",token,e.getMessage());

      throw new GateWayException(ResultCode.JWT_TOKEN_EXPIRE);
    }
  }


}
